
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Game extends JPanel implements MouseListener {
	static Timer timer;
	static Timer gameTime;

	RunState state = RunState.READY;

	static int arr[][] = new int[12][12];
	static int temparr[][] = new int[12][12];

	boolean blueLineVisible;
	boolean p1Visible;
	boolean p2Visible;
	boolean changeColor=false;

	int blueLineTime = 0;
	int OverTime = 180;
	int unlockCount = 0;
	int green = 255;
	static Box boxs[][] = new Box[10][10];
	static GameButton btn_start = null;
	static GameButton menubtn = null;
	static Sider sider=null;
	public static BufferedImage images[];
	static BufferedImage back;
	static BufferedImage btn_start_img;
	static BufferedImage overImg;
	static BufferedImage menu;
	static BufferedImage SiderImg;
	int clicktime = 0;
	static point point1 = new point();
	static point point2 = new point();
	List<point> list = null;

	int way[][] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
	static int data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,
						  0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
	static {
		images = new BufferedImage[20];
		try {
			images[0]  = ImageIO.read(new File("image/0.jpg"));
			images[1]  = ImageIO.read(new File("image/1.jpg"));
			images[2]  = ImageIO.read(new File("image/2.jpg"));
			images[3]  = ImageIO.read(new File("image/3.jpg"));
			images[4]  = ImageIO.read(new File("image/4.jpg"));
			images[5]  = ImageIO.read(new File("image/5.jpg"));
			images[6]  = ImageIO.read(new File("image/6.jpg"));
			images[7]  = ImageIO.read(new File("image/7.jpg"));
			images[8]  = ImageIO.read(new File("image/8.jpg"));
			images[9]  = ImageIO.read(new File("image/9.jpg"));
			images[10] = ImageIO.read(new File("image/10.jpg"));
			images[11] = ImageIO.read(new File("image/11.jpg"));
			images[12] = ImageIO.read(new File("image/12.jpg"));
			images[13] = ImageIO.read(new File("image/13.jpg"));
			images[14] = ImageIO.read(new File("image/14.jpg"));
			images[15] = ImageIO.read(new File("image/15.jpg"));
			images[16] = ImageIO.read(new File("image/16.jpg"));
			images[17] = ImageIO.read(new File("image/17.jpg"));
			images[18] = ImageIO.read(new File("image/18.jpg"));
			images[19] = ImageIO.read(new File("image/19.jpg"));
			back = ImageIO.read(new File("image/back.jpg"));

			
			btn_start_img = ImageIO.read(new File("image/btn_start.png"));
			overImg = ImageIO.read(new File("image/gameover.png"));
			menu=ImageIO.read(new File("image/menu.png"));
			SiderImg=ImageIO.read(new File("image/sider.png"));

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public static void main(String args[]) {
		
		btn_start = new GameButton(btn_start_img,150,350);
		menubtn = new GameButton(menu,0,0);
		menubtn.Height=50;
		menubtn.Width=50;
		sider = new Sider(SiderImg,-200,0);
		JFrame frame = new JFrame();

		frame.setSize(620, 690);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setTitle("连连看");
		Game game = new Game();
		game.setBounds(0, 0, 620, 660);

		game.addMouseListener(game);
		frame.add(game);
		frame.setVisible(true);
		game.start();

	}
	public void init(){
		for(int i=0;i<20;i++){data[i]=0;}
		Random rand = new Random();
		for (int i = 0; i < 10; i++) {
			for (int j = 0; j < 10; j++) {

				int n = rand.nextInt(20);
				int value=5;
				if(n%2==0){
					value++;
				}
				else{
					value--;
				}
				if (data[n] < value) {
					boxs[i][j] = new Box(images[n], (i + 1) * 50, (j + 1) * 50);
					boxs[i][j].Visible = true;
					arr[i + 1][j + 1] = n;
					data[n]++;
				} else {
					j--;
				}

			}
		}
		point1.x = 0;
		point1.y = 0;
		unlockCount=0;
		green=255;
		changeColor=false;

	}
	public void start() {
		for (int i = 0; i < 12; i++) {
			arr[0][i] = -1;
			arr[i][0] = -1;
			arr[11][i] = -1;
			arr[i][11] = -1;
		}
		timer = new Timer();
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				if(changeColor==true){
					green=green+(200-OverTime)/20;
					if(green+(190-OverTime)/10>255)changeColor=false;
				}else{
					green=green-(190-OverTime)/10;
					if(green-(190-OverTime)/10<128)changeColor=true;
				}
				repaint();
			}

		}, 10, 10);
		gameTime = new Timer();
		gameTime.schedule(new TimerTask(){
			@Override
			public void run(){
				if(state==RunState.RUNNING){
					if(OverTime>0){
						OverTime--;
						
					}
					else{
						state=RunState.OVER;
					}
				}

			}

		},1000,1000);
	}

	@Override
	public void paint(Graphics g) {
		if(state==RunState.READY){
			g.drawImage(back, 0, 0, 620, 660, null);
			g.drawImage(btn_start.img,btn_start.x,btn_start.y,btn_start.Width,btn_start.Height,null);
			g.drawImage(menubtn.img,menubtn.x,menubtn.y,menubtn.Width,menubtn.Height,null);
			drawMenu(g);
		}

		else if(state==RunState.RUNNING){
			g.drawImage(back, 0, 0, 620, 660, null);

			drawLine(g);
			for (int i = 0; i < 10; i++) {
				for (int j = 0; j < 10; j++) {
					if (boxs[i][j].Visible == true) {
						g.drawImage(boxs[i][j].img, boxs[i][j].x, boxs[i][j].y, boxs[i][j].Width, boxs[i][j].Height, null);

					}
				}
			}
			drawRect1(g);
			
			drawRect2(g);
			g.drawImage(menubtn.img,menubtn.x,menubtn.y,menubtn.Width,menubtn.Height,null);
			//g.drawImage(sider.img,sider.x,sider.y,sider.Width,sider.Height,null);
			drawTimeProgress(g);
			drawMenu(g);
			if(unlockCount==50){

				state=RunState.OVER;

			}
		}

		else if(state==RunState.OVER){
			g.drawImage(back, 0, 0, 620, 660, null);
			drawLine(g);
			for (int i = 0; i < 10; i++) {
				for (int j = 0; j < 10; j++) {
					if (boxs[i][j].Visible == true) {
							g.drawImage(boxs[i][j].img, boxs[i][j].x, boxs[i][j].y, boxs[i][j].Width, boxs[i][j].Height, null);

					}
				}
			}
				drawRect1(g);
		
				drawRect2(g);
		
				drawTimeProgress(g);
				g.drawImage(overImg,0,0,620,660,null);
				g.drawImage(menubtn.img,menubtn.x,menubtn.y,menubtn.Width,menubtn.Height,null);
				drawMenu(g);
			
				
			
		}
		 
	
	}

	void drawRect1(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		g2.setColor(new Color(0, 206, 209));
		g2.setStroke(new BasicStroke(5f));
		if (p1Visible) {
			g.drawRect(point1.x * 50, point1.y * 50, 50, 50);
		}

	}
	void drawMenu(Graphics g){

		g.drawImage(sider.img,sider.x,sider.y,sider.Width,sider.Height,null);
		sider.draw(g);
	}

	void drawRect2(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		g2.setColor(new Color(0, 206, 209));
		g2.setStroke(new BasicStroke(5f));
		if (p2Visible) {
			g.drawRect(point2.x * 50, point2.y * 50, 50, 50);
		}

	}

	void drawLine(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		g2.setColor(new Color(0, 206, 209));
		g2.setStroke(new BasicStroke(5f));
		if (blueLineVisible) {

			blueLineTime += 1;
			if (blueLineTime >= 10) {
				blueLineVisible = false;
				boxs[point1.x - 1][point1.y - 1].Visible = false;
				boxs[point2.x - 1][point2.y - 1].Visible = false;
				blueLineTime = 0;
				p1Visible = false;
				p2Visible = false;
				
			}
			for (int i = 0; i < list.size() - 1; i++) {
				g2.drawLine((list.get(i).x) * 50 + 25, (list.get(i).y) * 50 + 25, (list.get(i + 1).x) * 50 + 25,
						(list.get(i + 1).y) * 50 + 25);

			}

		}

	}
	void drawTimeProgress(Graphics g){
		g.setColor(new Color(0,green,0));
		g.fillRect(50,600,OverTime*500/180,20);
		g.setColor(Color.WHITE);
		g.drawRect(50,600,500,20);
		
		g.setFont(new Font("Arial" ,Font.BOLD, 14));
		g.drawString(String.valueOf(OverTime),300,615);
	}
	void copyArr() {
		for (int i = 0; i < 12; i++) {
			for (int j = 0; j < 12; j++) {
				temparr[i][j] = arr[i][j];
			}
		}
	}
	
	List<point> dfs(point p1, point p2, point pt, int time, int last_way) {
		int cnt = 1000;
		List<point> list = null;
		List<point> result = null;
		if (temparr[p1.x][p1.y] != temparr[p2.x][p2.y] || (p1.x == p2.x && p1.y == p2.y))
			return result;
		if (time > 2)
			return result;

		for (int i = 0; i < 4; i++)
		{
			pt.x += way[i][0];
			pt.y += way[i][1];
			if (pt.x < 0 || pt.y < 0 || pt.x > 11 || pt.y > 11) {			
				pt.x -= way[i][0];
				pt.y -= way[i][1];
				continue;
			}
			if (temparr[pt.x][pt.y] == -1)
			{
				point p = new point();
				p.x = pt.x;
				p.y = pt.y;
				if (last_way != i && last_way != -1)
				{

					list = dfs(p1, p2, p, time + 1, i);

				} else {

					list = dfs(p1, p2, p, time, i);

				}

				if (list != null)
				{

					if (list.size() < cnt)
					{
						cnt = list.size();
						result = list;

						result.add(p);

					}

				}

			} else {
				if (!(time == 2 && last_way != i))
				{
					if (pt.x == p2.x && pt.y == p2.y)
					{
						point p = new point();
						p.x = pt.x;
						p.y = pt.y;
						arr[pt.x][pt.y] = -1;

						result = new ArrayList<point>();
						result.add(p);
						pt.x -= way[i][0];
						pt.y -= way[i][1];

						return result;
					}
				}

			}
			pt.x -= way[i][0];
			pt.y -= way[i][1];
			

		}

		return result;
	}
	void checkBtnStartClick(int x,int y){
		if(btn_start.IsClick(x,y)){
			init();
			OverTime=180;
			state=RunState.RUNNING;

		}
	}
	boolean checkBtnMenuClick(int x,int y){
		if(menubtn.IsClick(x,y)){
			sider.Visible=true;
			return true;
		}
		else{
			sider.Visible=false;
		}
		return false;
	}
	boolean checkSiderMenuClick(int x,int y){
		if(sider.Visible==true){
			for(int i=0;i<sider.buttons.size();i++){

				if(sider.buttons.get(i).IsClick(x-200,y)){
					System.out.println("click");
					switch(i){
						case 0:
							init();
							OverTime=-180;
							state=RunState.READY;

							break;
						case 1:
							state=RunState.OVER;
							break;
						 default:
							break;

					}
					sider.Visible=false;
					return true;
					

				}

			}
				
		}
		return false;
		
	}
	void checkBoxClick(int x,int y){
		for (int i = 0; i < 10; i++) {
			for (int j = 0; j < 10; j++) {
				if (boxs[i][j].IsClick(x, y)) {
					// System.out.println(i + "/" + j);
					if (clicktime == 0) { 
						point1.x = i + 1;
						point1.y = j + 1;
						clicktime = 1;
						p1Visible = true;

					} else { 
						point2.x = i + 1;
						point2.y = j + 1;
						clicktime = 0;
						p2Visible = true;
						copyArr();
						point pt = new point();
						pt.x = point1.x;
						pt.y = point1.y;
						list = dfs(point1, point2, pt, 0, -1);
						if (list != null) {
							if (arr[point2.x][point2.y] == -1) {
								arr[point1.x][point1.y] = -1;
								list.add(point1);

								blueLineVisible = true;
								unlockCount++;
							}

						} else {
							p1Visible = false;
							p2Visible = false;
						}
					}

				}
			}
		}
	}

	@Override
	public void mouseClicked(MouseEvent e) {

	}
	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mousePressed(MouseEvent e) {
		if(checkSiderMenuClick(e.getX(),e.getY())){
			return;
		}
		if(checkBtnMenuClick(e.getX(),e.getY())){
			return;
		}
		switch(state){
			case READY:
			checkBtnStartClick(e.getX(),e.getY());
				break;
			case RUNNING:

				
				checkBoxClick(e.getX(),e.getY());
				
				break;
			case OVER:
				state=RunState.READY;

				break;

			

		}
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub

	}

}


